package org.xxpay.pay.channel.suile;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.xxpay.common.unify.AbstractPaymentConfig;
import org.xxpay.common.util.XML;
import org.xxpay.common.util.sign.CertDescriptor;
import org.xxpay.common.util.sign.encrypt.RSA;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.entity.TransOrder;
import org.xxpay.pay.channel.BaseTransNotify;

import java.security.PublicKey;
import java.util.Map;

/**
 * @Package org.xxpay.pay.channel.sand
 * @Class: SandPaymentNotifyService.java
 * @Description:
 * @Author leo
 * @Date 2019/4/11 17:58
 * @Version
 **/
@Component
public class SuileTransNotifyService extends BaseTransNotify {
    private final static String logPrefix = "【随乐代付回调】";

    private static CertDescriptor certDescriptor;
    static {
        try {
            certDescriptor = new CertDescriptor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getChannelName() {
        return SuileConfig.CHANNEL_NAME;
    }

    @Override
    public JSONObject doNotify(Object notifyData) {
        JSONObject obj = getRequestParameters(notifyData);
        Map<String, String> requestData = JSONObject.parseObject(obj.toJSONString(), Map.class);
        String data = "";
        for (Map.Entry<String, String> entry : requestData.entrySet()) {
            data += entry.getKey() + entry.getValue();
        }
        // 将字符串的所有空格替换成+字符
        data = data.replaceAll(" ", "+");
        _log.info("{}原始参数：{}", logPrefix, data);
        String []  base64 = data.split("\\|");
        JSONObject retObj = buildFailRetObj();
        try {
            String xml = new String(Base64.decodeBase64(base64[0]), "UTF-8");
            _log.info("{}xml参数：{}", logPrefix, xml);
            JSONObject origin = XML.xml2Map(xml);
            origin.put("sign", base64[1]);
            origin.put("xml", xml);
            _log.info("{}xml参数：{}", logPrefix, origin.toJSONString());
            if (!verifyPayParams(origin)) {
                retObj.put(PayConstant.RESPONSE_RESULT, SuileConfig.RESPONSE_RESULT_FAIL);
                return retObj;
            }
            TransOrder transOrder = (TransOrder) origin.get("transOrder");
            byte currStatus = transOrder.getStatus();
            // 如果当前订单已是成功状态，不在处理，直接返回成功
            if(currStatus == PayConstant.TRANS_STATUS_SUCCESS || currStatus == PayConstant.TRANS_STATUS_COMPLETE) {
                retObj.put(PayConstant.RESPONSE_RESULT, SuileConfig.RESPONSE_RESULT_SUCCESS);
                return retObj;
            }
            JSONObject notifyDetailObj = origin.getJSONArray("tranList").getJSONObject(0);
            String transOrderId = transOrder.getTransOrderId();
            String channelOrderNo = notifyDetailObj.getString("sn");
            String respCode = notifyDetailObj.getString("respCode");
            String respDesc = notifyDetailObj.getString("respDesc");
            if(StringUtils.equals(respCode, SuileConfig.RETURN_VALUE_SUCCESS)) {
                int updateTransOrderRows = rpcCommonService.rpcTransOrderService.updateStatus4Success(transOrderId, channelOrderNo);
                _log.info("更新转账订单状态为成功({}),transOrderId={},返回结果:{}", PayConstant.TRANS_STATUS_SUCCESS, transOrderId, updateTransOrderRows);
                if (updateTransOrderRows != 1) {
                    _log.error("{}更新代付状态失败,将transOrderId={},更新trnsStatus={}失败", logPrefix, transOrderId, PayConstant.TRANS_RESULT_SUCCESS);
                    retObj.put(PayConstant.RESPONSE_RESULT, "处理订单失败");
                    return retObj;
                }
                _log.error("{}更新代付状态成功,将transOrderId={},更新transStatus={}成功", logPrefix, transOrderId, PayConstant.TRANS_RESULT_SUCCESS);
                transOrder.setStatus(PayConstant.PAY_STATUS_SUCCESS);
            } else if(StringUtils.equals(respCode, SuileConfig.RETURN_VALUE_HANDING)) {
                transOrder.setStatus(PayConstant.TRANS_STATUS_TRANING);
            } else {
                int updateTransOrderRows = rpcCommonService.rpcTransOrderService.updateStatus4Fail(transOrderId,
                        respCode, respDesc, channelOrderNo);
                _log.info("更新代付订单状态为失败({}),transOrderId={},返回结果:{}", PayConstant.TRANS_STATUS_FAIL, transOrderId, updateTransOrderRows);
                if (updateTransOrderRows != -1) {
                    _log.error("{}更新代付状态失败,将transOrderId={},更新trnsStatus={}失败", logPrefix, transOrderId, PayConstant.TRANS_RESULT_SUCCESS);
                    retObj.put(PayConstant.RESPONSE_RESULT, "处理订单失败");
                    return retObj;
                }
                transOrder.setStatus(PayConstant.TRANS_STATUS_FAIL);
            }

            // 业务系统后端通知
            baseNotify4MchTrans.doNotify(transOrder, true);
            retObj.put(PayConstant.RESPONSE_RESULT, SuileConfig.RESPONSE_RESULT_SUCCESS);
        } catch(Exception e) {
            _log.error("{}参数解析异常", e);
        }
        return retObj;
    }

    private boolean verifyPayParams(JSONObject payContext) {
        // 查询transOrder记录
        String transOrderId = payContext.getString("tranId");
        TransOrder transOrder = rpcCommonService.rpcTransOrderService.findByTransOrderId(transOrderId);
        if (ObjectUtils.isEmpty(transOrder)) {
            _log.error("Can't found transOrder form db. transOrderId={}, ", transOrderId);
            payContext.put("retMsg", "Can't found payOrder");
            return false;
        }

        SuileConfig suileConfig = new SuileConfig(getTransParam(transOrder));

        boolean isVerify = signVerify(payContext.getString("xml"), payContext.getString("sign"), suileConfig);
        if(!isVerify) {
            _log.error("验证签名失败. transOrderId={}, ", transOrderId);
            payContext.put("retMsg", "验证签名失败");
            return false;
        }

        payContext.put("transOrder", transOrder);
        return true;
    }

    public boolean signVerify(String body, String sign, AbstractPaymentConfig config) {
        certDescriptor.initPublicCert(config.getPublicStorePath());
        PublicKey publicKey = certDescriptor.getPublicCert().getPublicKey();
        byte[] bodyMd5Bytes = DigestUtils.md5(body);
        return RSA.verify(bodyMd5Bytes, sign, publicKey);
    }

}
